package io.sundial.console.task.web;

import io.sundial.console.Pagination;
import io.sundial.console.task.core.Logging;
import io.sundial.console.task.core.Plan;
import io.sundial.console.task.dto.LoggingVO;
import io.sundial.console.task.dto.TaskVO;
import io.sundial.console.task.service.LoggingService;
import io.sundial.console.task.service.PlanService;
import io.sundial.console.taskgroup.core.Period;
import io.sundial.console.taskgroup.core.Taskgroup;
import io.sundial.console.taskgroup.service.TaskgroupService;
import io.sundial.planning.Planner;
import io.sundial.repository.RepositoryException;
import io.sundial.task.Task;
import org.quartz.CronExpression;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.text.ParseException;
import java.util.*;

/**
 * 任务控制器
 *
 * @author Payne 646742615@qq.com
 * 2019/1/4 16:09
 * @tag 任务
 */
@CrossOrigin
@RestController
@RequestMapping("/api/task")
public class TaskController {

    @Resource
    private TaskgroupService taskgroupServiceBean;

    @Resource
    private Planner planner;

    @Resource
    private PlanService planServiceBean;

    @Resource
    private LoggingService loggingServiceBean;

    @PostMapping
    @ResponseBody
    public TaskCreateResult create(@RequestBody @Valid TaskCreateParam param) throws RepositoryException {
        TaskCreateResult result = new TaskCreateResult();

        String group = param.getGroup();
        Taskgroup taskgroup = taskgroupServiceBean.find(group);
        if (taskgroup == null) {
            return result.error(400, "任务组不存在：" + group);
        }

        Period period = param.getPeriod();
        String expression = param.getExpression();
        if (period == null) {
            period = taskgroup.getPeriod();
            expression = taskgroup.getExpression();
        }

        String cronExpression = period.toCronExpression(expression);
        boolean valid = cronExpression == null || CronExpression.isValidExpression(cronExpression);
        if (!valid) {
            return result.error(400, "不正确的表达式");
        }

        Task.Key key = new Task.Key(param.getName(), param.getGroup());
        Task task = new Task();
        task.setName(param.getName());
        task.setGroup(param.getGroup());
        task.setJobName(param.getJobName());
        task.setJobGroup(param.getJobGroup());
        task.setDescription(param.getDescription());
        task.setDateStart(param.getDateStart());
        task.setDateEnd(param.getDateEnd());
        task.setPriority(param.getPriority());
        task.setShardingTotal(1);
        task.setJobArguments(param.getJobArguments());
        task.setCronExpression(cronExpression);
        task.setChildren(toTaskKeys(param.getChildren()));

        planner.save(key, task);

        return result;
    }

    @GetMapping
    @ResponseBody
    public TaskSearchResult search(@Valid TaskSearchParam param) {
        TaskSearchResult result = new TaskSearchResult();

        result.setParam(param);

        Pagination<Plan> pagination = planServiceBean.search(param.getKeyword(), param.getGroup(), param.getPageNo(), param.getPageSize());
        result.setTotal(pagination.getTotal());
        List<TaskVO> tasks = new ArrayList<>();
        List<Plan> items = pagination.getItems();
        for (Plan item : items) {
            Task task = planner.find(new Task.Key(item.getKey().getName(), item.getKey().getGroup()));
            if (task == null) {
                continue;
            }
            TaskVO taskVO = new TaskVO(task);
            tasks.add(taskVO);
        }
        result.setItems(tasks);

        return result;
    }

    private Set<Task.Key> toTaskKeys(List<TaskChild> children) {
        Set<Task.Key> keys = new LinkedHashSet<>();
        if (children == null || children.isEmpty()) {
            return keys;
        }
        for (TaskChild child : children) {
            keys.add(new Task.Key(child.getName(), child.getGroup()));
        }
        return keys;
    }

    @GetMapping("/{taskGroup}/{taskName}")
    @ResponseBody
    public LoggingSearchResult logging(@PathVariable("taskGroup") String taskGroup, @PathVariable("taskName") String taskName, @Valid LoggingSearchParam param) throws ParseException {
        LoggingSearchResult result = new LoggingSearchResult();
        result.setParam(param);

        Pagination<Logging> pagination = loggingServiceBean.search(
                taskGroup,
                taskName,
                param.getDateStart(),
                param.getDateEnd(),
                param.getStatus(),
                param.getPageNo(),
                param.getPageSize()
        );

        result.setTotal(pagination.getTotal());

        List<LoggingVO> vos = new ArrayList<>();
        List<Logging> items = pagination.getItems();
        for (Logging item : items) {
            LoggingVO vo = new LoggingVO();
            vo.setTime(new Date(item.getKey().getTime()));
            vo.setCode(item.getCode());
            vo.setMessage(item.getMessage());
            vo.setStatus(item.getStatus());
            vo.setResult(item.getResult());
            vos.add(vo);
        }
        result.setItems(vos);

        return result;
    }

}
